import com.powerfl.frm.taf.*;

import flash.events.*;
import flash.text.*;
import flash.utils.*;

import org.audiofx.mp3.*;

final public function byteToString( $byte:ByteArray ):String{
	var result:Vector.<String>, i:uint, j:uint, position:int;
	position = $byte.position; 
	$byte.position = 0;
	result = new Vector.<String>(); 
	for( i = 0, j = $byte.length; i < j ; ++i ){
		result[result.length] = ENCODE.charAt( $byte.readByte() + 128 );
	}
	$byte.position = position;
	return result.join( '' );
}
final public function byteFromString( $String:String ):ByteArray{
	var result:ByteArray, i:uint, j:uint;
	result = new ByteArray;
	for( i = 0, j = $String.length; i < j ; ++i ){
		result.writeByte( ENCODE.indexOf( $String.charAt( i ) ) - 128 );
	}
	return result;
}
final public function byteGet( $byte:ByteArray, $length:int = 0 ):ByteArray{
	var result:ByteArray;
	result = new ByteArray;
	$byte.readBytes( result, 0, $length );
	return result;
}
final public function resGet( $res:ByteArray, $end:*, $isFile:Boolean = false ):void{
	$res.position = 0;
	if( $end is String ){
		$end = flowGet( $end );
	}
	resGet_( $res, $end, poolPullRes(), $isFile );
}
private function resLoader( $byte:ByteArray, $end:Function ):void{
	var loader:Loader, context:LoaderContext; 
	loader = new Loader;
	loader.contentLoaderInfo.addEventListener( Event.COMPLETE, $end );
	context = new LoaderContext;
	if( 'allowLoadBytesCodeExecution' in context ){
		context.allowLoadBytesCodeExecution = true;
	}
	context.applicationDomain = new ApplicationDomain;
	loader.loadBytes( $byte, context );
}
// ['image', 'bitmap', 'mp3', 'svg', 'byte', 'string', 'font', 'swfres'];
private function resGet_( $res:ByteArray, $end:Function, $result:TAFres, $isFile:Boolean ):void{
	var temp:ByteArray, type:int, name:String, data:*, body:ByteArray;
	
	if( $res.position ===  $res.length ){
		$end( $result );
		return;
	}
		
	temp = byteGet( $res, $res.readUnsignedInt() );
	temp.uncompress();
	temp.position = 0;	
	
	type = temp.readByte(); 
	name = trim( temp.readUTF() );
	body = byteGet( temp );
	body.position = 0;
	if( $isFile ){
		$result.files[name] = body;
	}
	switch( type ){
	case 0:
		return resLoader( body, function( $e:Event ):void{
			$e.target.removeEventListener( $e.type, arguments.callee );
			$result.bitmap[name] = $e.target.content.bitmapData.clone();
			$e.target.content.bitmapData.dispose();
			resGet_( $res, $end, $result, $isFile );
		} );
	case 1:
		$result.bitmap[name] = bitmapData( body.readShort(), body.readShort() );
		$result.bitmap[name].setPixels( $result.bitmap[name].rect, byteGet( body ) );
		if( $isFile ){
			$result.files[name] = pngEncode( $result.bitmap[name] );
		}
		break;
	case 2:
		byteToSound( body, function( $sound:Sound ):void{
			$result.sound[name] = $sound;
			resGet_( $res, $end, $result, $isFile );
		} );
		return;
	case 4:
		$result.byte[name] = body;
		break;
	case 5:
		$result.string[name] = body.readUTFBytes( body.bytesAvailable );
		break;
	case 6:
		return resLoader( body, function( $e:Event ):void{
			var cls:Class, key:*, fontName:String;
			$e.target.removeEventListener( $e.type, arguments.callee );
			if( name.indexOf( '@' ) > -1 ){
				name = name.substr( name.indexOf( '@' ) + 1 )
			}
			cls = $e.target.applicationDomain.getDefinition( name ) as Class;
			for each( key in describeType( cls ).variable ){
				fontName = key.@name;
				if( fontName.substring( 0, 4 ) === 'FONT' ){
					Font.registerFont( cls[fontName] );
				}
			}
			resGet_( $res, $end, $result, $isFile );
		} );
	}
	resGet_( $res, $end, $result, $isFile );
}

final public function byteToSound( $MP3:ByteArray, $end:Function ):void{
	var i:int, parser:MP3Parser, swfBytes:ByteArray, 
		swfSizePosition:uint, audioSizePosition:uint, sampleSizePosition:uint,
		frameCount:uint, byteCount:uint, seg:ByteArraySegment,
		currentPos:uint, swfBytesLoader:Loader;
		
	parser = new MP3Parser;
	parser.loadBytes( $MP3 );

	swfBytes = new ByteArray
	swfBytes.endian = Endian.LITTLE_ENDIAN;
	
	for( i = 0 ; i < SoundClassSwfByteCode.soundClassSwfBytes1.length ; ++i ){
		swfBytes.writeByte( SoundClassSwfByteCode.soundClassSwfBytes1[i] );
	}
	swfSizePosition =swfBytes.position;
	swfBytes.writeInt(0);
	
	for( i = 0 ; i < SoundClassSwfByteCode.soundClassSwfBytes2.length ; ++i ){
		swfBytes.writeByte( SoundClassSwfByteCode.soundClassSwfBytes2[i] );
	}
	
	audioSizePosition = swfBytes.position;
	swfBytes.writeInt( 0 );
	swfBytes.writeByte( 1 );
	swfBytes.writeByte( 0 );
	parser.writeSwfFormatByte( swfBytes );
	
	sampleSizePosition = swfBytes.position;
	swfBytes.writeInt(0);
	swfBytes.writeByte(0);
	swfBytes.writeByte(0);
	
	frameCount = byteCount = 0;
	
	while( seg = parser.getNextFrame() ){
		swfBytes.writeBytes( seg.byteArray, seg.start, seg.length );
		byteCount += seg.length;
		++frameCount;
	}
	if( byteCount === 0 ){
		return;
	}
	byteCount += 2;
	
	currentPos = swfBytes.position;
	swfBytes.position = audioSizePosition;
	swfBytes.writeInt( byteCount + 7 );
	swfBytes.position = sampleSizePosition;
	swfBytes.writeInt( frameCount*1152 );
	swfBytes.position = currentPos;
	for( i = 0 ; i < SoundClassSwfByteCode.soundClassSwfBytes3.length ; ++i ){
		swfBytes.writeByte( SoundClassSwfByteCode.soundClassSwfBytes3[i] );
	}
	swfBytes.position=swfSizePosition;
	swfBytes.writeInt(swfBytes.length);
	swfBytes.position=0;
	
	resLoader( swfBytes, function( $e:Event ):void{
		var cls:Class;
		$e.target.removeEventListener( $e.type, arguments.callee );
		cls = $e.target.applicationDomain.getDefinition("SoundClass") as Class;
		$end( new cls );
	} );
}